home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / emac16as.arc / BUFFERS.ASM next >
Assembly Source File  |  1990-04-01  |  20KB  |  840 lines

  1. ;History:413,1
  2. ;Sat Aug 19 20:49:16 1989 When creating a new buffer, try to avoid compressing memory.
  3. ;10-10-88 22:10:05 add inverse_seg to adjust_list.
  4. ;06-03-88 23:47:57 improve buffer_check
  5. ;05-26-88 23:25:49 added assumes in init_all_buffers
  6. ;05-26-88 23:24:13 remove external reference to adjust_buffers
  7. ;04-19-88 22:23:33 restore ax after returning from a buffer_free.
  8. ;03-29-88 20:59:24 store ' c' or ' e' after expand or compress.
  9. ;03-13-88 23:01:42 after doing our work, store '  ' to debug.
  10. ;12-11-87 06:52:36 add buffer_check
  11. ;12-08-87 22:52:36 add calls to store_debug
  12. ;12-06-87 00:32:51 add support for four formSegs.
  13. ;12-06-87 00:18:16 let init_forms allocate as many buffers as it wants.
  14. ;11-16-87 23:17:35 make memsize private to buffers.asm
  15. ;11-10-87 23:02:55 more work to do....
  16. ;11-10-87 21:46:38 ensure that we can treat 'data' as if it were a 'bufseg'.
  17. ;11-09-87 23:12:03 start writing buffer_free.
  18.     .xlist
  19.     include    memory.def
  20.  
  21. bufseg    segment    public
  22.  
  23.     extrn    prev_buffer: word    ;= segment of prev buffer (0 if none)
  24.     extrn    next_buffer: word    ;= segment of next buffer (0 if none)
  25.  
  26.     extrn    toptop: word
  27.     extrn    topbot: word
  28.     extrn    bottop: word
  29.     extrn    botbot: word
  30.     extrn    new_size: word
  31.  
  32. memsize        dw    ?
  33.  
  34.     extrn    bufseg_size: word
  35.  
  36. bufseg    ends
  37.  
  38.  
  39. data    segment    byte public
  40.  
  41.     extrn    lomem: byte, lomem_end: byte
  42.  
  43.     public    textseg
  44. textseg        dw    ?        ;bufseg of current text buffer.
  45. current_seg    dw    ?        ;bufseg of buffer_free caller.
  46. saveDS        dw    ?
  47. saveES        dw    ?
  48.  
  49. last_para    dw    ?        ;segment after highest buffer
  50. memory_end    dw    ?        ;segment after highest buffer right now.
  51. num_buffers    dw    ?
  52. amount_needed    dw    ?        ;amount that we need to be free.
  53. free_paras    dw    ?        ;number of free paragraphs left.
  54. insert_number    dw    ?        ;number of buffer being inserted from.
  55. insert_mark    db    ?        ;mark in buffer being inserted from.
  56.  
  57.     extrn    w1_windseg: word, w2_windseg: word    ;from redisp.asm
  58.     extrn    inverse_seg: word    ;from redisp.asm
  59.     extrn    syntax_seg: word    ;from mintform.asm
  60.     extrn    formSeg0: word        ;from mintform.asm
  61.     extrn    formSeg1: word        ;from mintform.asm
  62.     extrn    formSeg2: word        ;from mintform.asm
  63.     extrn    formSeg3: word        ;from mintform.asm
  64.  
  65. adjust_list    label    word
  66.     dw    textseg            ;have to adjust this one.
  67.     dw    current_seg
  68.     dw    w1_windseg        ;from redisp.asm, window one's buffer.
  69.     dw    w2_windseg        ;from redisp.asm, window two's buffer.
  70.     dw    inverse_seg
  71.     dw    syntax_seg
  72.     dw    formSeg0        ;from mintform.asm
  73.     dw    formSeg1        ;from mintform.asm
  74.     dw    formSeg2        ;from mintform.asm
  75.     dw    formSeg3        ;from mintform.asm
  76.     dw    saveDS
  77.     dw    saveES
  78.     dw    0
  79.  
  80. data    ends
  81.  
  82.  
  83. code    segment    byte public
  84. ;all the routines in this segment are entered with ds=data, es=data
  85.     assume    cs:code, ds:data, es:data, ss:data
  86.  
  87.     extrn    init_forms: near
  88.  
  89. movmem    macro
  90.     local    x
  91.     shr    cx,1
  92.     jnc    x
  93.     movsb
  94. x:    rep    movsw
  95.     endm
  96.  
  97.  
  98. comment /
  99.  
  100.     buffers:
  101.  
  102.     data
  103.     mint string
  104.     text
  105.     ...
  106.  
  107. a buffer is initially set with bottop=botbot=end of buffer.  Then the buffer
  108. is initialized.
  109. /
  110.  
  111.     public    init_all_buffers
  112. init_all_buffers:
  113. ;enter with bx=> first paragraph of unavailable memory.
  114. ;exit with cy if no buffer available.
  115.     mov    memory_end,bx        ;remember where memory ends.
  116.     mov    last_para,bx        ;remember where memory ends.
  117.     assume    ds:bufseg
  118.     mov    prev_buffer,0        ;only one buffer so far.
  119.     mov    next_buffer,0
  120.     mov    ax,offset lomem
  121.     mov    topbot,ax
  122.     mov    bottop,ax
  123.     mov    botbot,offset lomem_end
  124.     assume    ds:data
  125.     call    init_forms        ;create as many buffers as init_forms needs.
  126.     jc    init__all_buffers_1
  127.     mov    cx,offset bufseg_size
  128.     call    new_buffer        ;create a new buffer.
  129.     jc    init__all_buffers_1
  130.     assume    ds:bufseg
  131.     call    select_buffer        ;make this the current buffer.
  132.     call    init_vars$        ;init most everything
  133.     call    init_marks        ;init the rest.
  134.     clc
  135.     push    es
  136.     pop    ds
  137.     assume    ds:data
  138. init__all_buffers_1:
  139.     ret
  140.  
  141.  
  142.     public    percent_full
  143. percent_full:
  144. ;return the percent full amount in ax.
  145. ;destroy ax,cx,dx.
  146.     push    ds
  147.     mov    ds,textseg
  148.     assume    ds:bufseg
  149.     mov    ax,100
  150.     mov    cx,memsize
  151.     jcxz    percent_full_1
  152.     mov    ax,botbot        ;compute the size of the buffer
  153.     sub    ax,bottop
  154.     add    ax,topbot
  155.     sub    ax,toptop
  156.     mov    dx,0
  157.     div    cx
  158.     cmp    dx,0
  159.     je    percent_full_1
  160.     inc    ax
  161. percent_full_1:
  162.     pop    ds
  163.     assume    ds:data
  164.     ret
  165.  
  166.  
  167.     public    buffer_allocate
  168. buffer_allocate:
  169. ;entry:
  170. ;  case cx of
  171. ;    -1..-32768: report the current buffer number.
  172. ;      exit: ax=current buffer number.
  173. ;    0: create a new buffer.
  174. ;      exit: ax=new buffer number if enough memory, ax=0 otherwise.
  175. ;    1..32767:
  176. ;      entry: cx=buffer number to select, ax=0 for read/write buffer.
  177. ;      exit: ax=buffer number if it exists, ax=0 otherwise.
  178.     jcxz    buffer_allocate_2
  179.     or    cx,cx            ;if cx<0, return buffer number.
  180.     js    buffer_allocate_4
  181.     call    find_buffer
  182.     jc    buffer_allocate_5    ;buffer not found.
  183.  
  184.     push    ds
  185.     mov    ds,dx            ;get the current buffer back.
  186.     call    select_buffer
  187.     pop    ds
  188.  
  189.     jmp    buffer_allocate_4
  190.  
  191. buffer_allocate_5:
  192.     mov    ax,0            ;buffer not found.
  193.     jmp    short buffer_allocate_1
  194. buffer_allocate_2:
  195. ;create a new buffer.
  196.     mov    cx,offset bufseg_size
  197.     call    new_buffer
  198.     mov    ax,0            ;failed to create buffer - report it.
  199.     jc    buffer_allocate_1
  200.     assume    ds:bufseg
  201.     call    select_buffer        ;make this the current buffer.
  202.     call    init_vars$        ;init most everything
  203.     call    init_marks        ;init the rest.
  204.     push    es
  205.     pop    ds
  206.     assume    ds:data
  207. buffer_allocate_4:
  208. ;return the current buffer number.
  209.     mov    bx,textseg
  210.     call    buffer_number        ;return number in ax.
  211. buffer_allocate_1:
  212.     push    es
  213.     pop    ds
  214.     assume    ds:data
  215.     ret
  216.  
  217.  
  218.     public    buffer_insert
  219. buffer_insert:
  220. ;enter with al=mark, cx=buffer number.
  221. ;insert the text between point and mark from the given buffer.
  222. ;exit with nc if ok, cy if the given buffer doesn't exist, or the specified
  223. ;  text won't fit.
  224.     mov    insert_number,cx
  225.     mov    insert_mark,al
  226.  
  227.     call    find_buffer        ;find their buffer.
  228.     jc    buffer_insert_1        ;not found.
  229.  
  230. ;get the size of the inserted text, and make sure we have that much free
  231. ;space.
  232.     push    ds
  233.     mov    ds,dx
  234.     assume    ds:bufseg
  235.     mov    al,insert_mark
  236.     call    read_mark$        ;we're just interested in the count.
  237.     mov    ax,textseg        ;now free that many bytes.
  238.     call    buffer_free
  239.     pop    ds
  240.     assume    ds:data
  241.     jc    buffer_insert_1        ;go if it won't fit.
  242.  
  243. ;now find the buffer again, get the mark, and insert it.
  244.     mov    cx,insert_number
  245.     call    find_buffer        ;this should ALWAYS return nc.
  246.     mov    al,insert_mark
  247.     mov    ds,dx
  248.     assume    ds:bufseg
  249.     call    read_mark$
  250.     mov    ax,ds
  251.     mov    ds,textseg
  252.     call    insert_string$        ;this should ALWAYS return nc.
  253.     jmp    short buffer_insert_2
  254. buffer_insert_1:
  255.     stc
  256. buffer_insert_2:
  257.     push    es            ;restore ds.
  258.     pop    ds
  259.     assume    ds:data
  260.     ret
  261.  
  262.  
  263.     public    compact_buffers
  264. compact_buffers:
  265. ;exit with bx=first unused paragraph.
  266.     call    compress
  267.     push    ds
  268.     mov    ds,textseg
  269.     assume    ds:bufseg
  270. ;    mov    cx,1000h        ;give the current buffer all that
  271. ;    call    adjust_new_size        ;  we can.
  272.     call    expand
  273.     call    get_last_buffer        ;get ds = paragraph of last buffer.
  274.     call    buffer_paragraphs    ;get the size of it.
  275.     mov    bx,ds
  276.     add    bx,cx
  277.     pop    ds
  278.     mov    last_para,bx
  279.     ret
  280.  
  281.  
  282.     public    uncompact_buffers
  283. uncompact_buffers:
  284.     mov    ax,memory_end
  285.     mov    last_para,ax
  286.     ret
  287.  
  288.  
  289. compress:
  290. ;move all the buffers as low in memory as they'll go.
  291. ;exit with bx=first unused paragraph, num_buffers set to the number of buffers.
  292.     mov    ax,'*c'
  293.     call    store_debug
  294.  
  295.     push    ds
  296.     assume    ds:bufseg
  297.  
  298.     mov    num_buffers,0
  299.  
  300.     mov    ax,ds            ;get set to compress data.
  301.     mov    es,ax
  302.     mov    di,topbot        ;put the bottom at the end of the top.
  303.     mov    si,bottop        ;have to get the copy, just in case.
  304.     mov    bottop,di        ;save the new bottop.
  305.     mov    cx,botbot
  306.     sub    cx,si            ;same as sub cx,bottop
  307.     movmem
  308.     mov    botbot,di
  309.  
  310. compress_4:
  311.     inc    num_buffers
  312.     call    buffer_paragraphs
  313.     mov    new_size,cx        ;remember it for later.
  314.     cmp    next_buffer,0        ;was this the last buffer in memory?
  315.     je    compress_3    ;yes - we're done.
  316.  
  317.     call    move_buffer_lower
  318.     jmp    compress_4
  319. compress_3:
  320.     mov    bx,ds            ;get the para of the last buffer.
  321.  
  322.     call    buffer_paragraphs
  323.     add    bx,cx            ;compute the first free segment.
  324.  
  325.     pop    ds
  326.     assume    ds:data
  327.  
  328.     mov    ax,last_para        ;get the end of memory.
  329.     sub    ax,bx            ;compute the amount free.
  330.     mov    free_paras,ax        ;remember it.
  331.  
  332.     mov    ax,' c'
  333.     call    store_debug
  334.  
  335.     ret
  336.  
  337.  
  338.     public    find_buffer
  339. find_buffer:
  340. ;enter with cx=buffer number.
  341. ;exit with nc, dx set to that buffer if it exists, cy otherwise.
  342.     push    ds
  343.     assume    ds:bufseg
  344.     add    cx,4            ;allow for the forms buffer(s).
  345. find_buffer_1:
  346.     mov    dx,next_buffer
  347.     cmp    dx,0            ;at the end?
  348.     je    find_buffer_2
  349.     mov    ds,dx
  350.     loop    find_buffer_1
  351.     mov    dx,ds            ;get the current buffer back.
  352.     pop    ds
  353.     clc
  354.     ret
  355. find_buffer_2:
  356.     pop    ds
  357.     stc
  358.     ret
  359.     assume    ds:data
  360.  
  361.  
  362.     public    new_buffer
  363. new_buffer:
  364. ;create a new buffer of size cx.
  365. ;exit with cy if there's not enough memory for a new buffer, or else return
  366. ;  with ds = new buffer.
  367.  
  368. ;first we try it by compressing just the last buffer.
  369.     push    cx
  370.  
  371.     push    cx
  372.     call    compress_last        ;compress just the last buffer.
  373.     pop    cx
  374.     call    new_buffer_subr
  375.     pop    cx
  376.     jnc    new_buffer_3        ;if it worked, we're okay.
  377.  
  378.     push    cx
  379.     call    compress        ;otherwise, compress memory.
  380.     pop    cx
  381.     call    new_buffer_subr
  382. new_buffer_3:
  383.     ret
  384.  
  385.  
  386. compress_last:
  387. ;exit with the last buffer in memory compressed.
  388.  
  389. compress_last_1:
  390.     assume    ds:bufseg
  391.     mov    dx,ds            ;remember the current buffer.
  392.     mov    ax,next_buffer        ;keep going until we have the
  393.     mov    ds,ax            ;  last buffer.
  394.     or    ax,ax
  395.     jne    compress_last_1
  396.  
  397.     assume    es:bufseg
  398.     mov    ds,dx            ;get the para of the last buffer.
  399.     mov    es,dx
  400.  
  401.     mov    di,topbot
  402.     mov    si,es:bottop        ;have to get the copy, just in case.
  403.     mov    es:bottop,di        ;save the new bottop.
  404.     mov    cx,es:botbot
  405.     sub    cx,si            ;same as sub cx,bottop
  406.     movmem
  407.     mov    es:botbot,di
  408.  
  409.     mov    ax,data
  410.     mov    es,ax
  411.     mov    ds,ax
  412.     assume    ds:data, es:data
  413.  
  414.     ret
  415.  
  416.  
  417. new_buffer_subr:
  418. ;see if there's enough memory for the new buffer, and create it if there is.
  419.     push    cx
  420.  
  421. new_buffer_2:
  422.     assume    ds:bufseg
  423.     mov    dx,ds            ;remember the current buffer.
  424.     mov    ax,next_buffer        ;keep going until we have the
  425.     mov    ds,ax            ;  last buffer.
  426.     or    ax,ax
  427.     jne    new_buffer_2
  428.  
  429.     mov    ds,dx            ;get the para of the last buffer.
  430.     call    buffer_paragraphs    ;compute the size of it.
  431.     add    dx,cx            ;find the end of it.
  432.  
  433.     pop    cx
  434.     mov    ax,cx
  435.     add    ax,0fh            ;get the size rounded up.
  436.     shr    ax,1
  437.     shr    ax,1
  438.     shr    ax,1
  439.     shr    ax,1
  440.     add    ax,dx
  441.     cmp    ax,last_para        ;is there enough memory for new buffer?
  442.     jae    new_buffer_1        ;no.
  443.     mov    next_buffer,dx        ;link to the new buffer.
  444.     mov    ax,ds
  445.     mov    ds,dx
  446.     mov    prev_buffer,ax        ;link back to the old buffer.
  447.     mov    next_buffer,0        ;and no link to a new buffer.
  448.     mov    topbot,cx        ;start with an empty buffer.
  449.     mov    bottop,cx
  450.     mov    botbot,cx
  451.     clc
  452.     ret
  453. new_buffer_1:
  454.     push    es
  455.     pop    ds
  456.     assume    ds:data
  457.     stc
  458.     ret
  459.  
  460.  
  461. code    ends
  462.  
  463.  
  464. code    segment    byte public
  465. ;all the code in this segment is entered with ds=bufseg, es=data
  466.     assume    cs:code, ds:bufseg, es:data
  467.  
  468. ;the following externs are in 'memory'
  469.     extrn    init_vars$: near
  470.     extrn    insert_string$: near
  471.     extrn    read_mark$: near
  472.  
  473.  
  474. ;the following externs are in 'marks'
  475.     extrn    init_marks: near
  476.  
  477. ;the following externs are in machine dependent.
  478.     extrn    store_debug: near
  479.  
  480.     public    buffer_free, expand, adjust_all, adjust_new_size
  481.     public    adjust_segments, select_buffer, move_buffer_higher
  482.     public    move_buffer_lower, buffer_paragraphs
  483.  
  484.  
  485.     public    buffer_check
  486. buffer_check:
  487. ;exit with zr if all is ok, nz if we have a bad link.
  488.     push    ds
  489.     mov    ax,ss
  490.     mov    ds,ax
  491.     mov    cx,256
  492. buffer_check_1:
  493.     cmp    next_buffer,0        ;if we're done, exit.
  494.     je    buffer_check_2
  495.     mov    ax,ds            ;remember this buffer.
  496.  
  497.   if 0
  498.     mov    bx,botbot
  499.     add    bx,10h            ;round up to next paragraph.
  500.     rcr    bx,1            ;ensure that 65536 bytes becomes
  501.     shr    bx,1            ; 1000h paragraphs.
  502.     shr    bx,1
  503.     shr    bx,1
  504.     add    bx,ax            ;compute the next possible location
  505.     cmp    bx,next_buffer        ;  for the next buffer.
  506.     ja    buffer_check_2        ;go if we somehow overlap.
  507.   endif
  508.  
  509.     mov    ds,next_buffer        ;go to the next buffer.
  510.     cmp    ax,prev_buffer        ;does the next buffer point to us?
  511.     loope    buffer_check_1        ;keep going if we're still ok.
  512. buffer_check_2:
  513.     pop    ds
  514.     ret
  515.  
  516.  
  517.  
  518.     public    buffer_number
  519. buffer_number:
  520. ;enter with bx=paragraph of buffer.
  521. ;exit with ax=number of buffer.
  522.     push    ds
  523.     mov    ax,ss
  524.     mov    ds,ax
  525.     xor    ax,ax
  526. buffer_number_1:
  527.     mov    dx,ds
  528.     cmp    dx,bx            ;is this the one we're looking for.
  529.     je    buffer_number_2        ;yes - we've got its number.
  530.     mov    ds,next_buffer        ;get the next buffer
  531.     inc    ax
  532.     jmp    buffer_number_1
  533. buffer_number_2:
  534.     pop    ds
  535.     sub    ax,4            ;allow for the forms buffer(s).
  536.     ret
  537.  
  538.  
  539. buffer_free:
  540. ;ensure that the buffer in ax has cx bytes free.  If it doesn't, reallocate
  541. ;  memory between the buffers.  Return with cy if we cannot get enough memory.
  542. ;  return with nc, ax = new location of buffer.
  543.     mov    saveDS,ds
  544.     mov    ds,ax
  545.     assume    ds:bufseg, es:nothing
  546.     mov    ax,bottop        ;get the free space size.
  547.     sub    ax,topbot
  548.     cmp    cx,ax            ;go if we have that much space.
  549.     ja    buffer_free_1
  550.     mov    ax,ds
  551.     mov    ds,saveDS
  552.     clc
  553.     ret
  554. buffer_free_1:
  555.  
  556.     push    bx
  557.     push    cx
  558.     push    dx
  559.     push    si
  560.     push    di
  561.     mov    saveES,es
  562.  
  563.     mov    amount_needed,cx    ;remember how much we need.
  564.  
  565.     mov    current_seg,ds
  566.     mov    ax,ss
  567.     mov    ds,ax
  568.     call    compress        ;move them down all the way.
  569.     mov    ds,current_seg
  570.  
  571. ;compact buffers also sets new_size to the new total size of the buffer,
  572. ;  and sets num_buffers to the number of buffers, and sets free_paras to
  573. ;  the number of free paragraphs.
  574.     mov    cx,amount_needed    ;compute the amount for this buffer.
  575.     add    cx,0fh
  576.     rcr    cx,1            ;ensure that 65536 bytes becomes
  577.     shr    cx,1            ; 1000h paragraphs.
  578.     shr    cx,1
  579.     shr    cx,1
  580.     cmp    cx,ax            ;do we have that much?
  581.     ja    buffer_free_2        ;  no - it's hopeless.
  582.     mov    ax,new_size        ;get the current size of the buffer.
  583.     add    ax,cx            ;  add in the size that we need.
  584.     cmp    ax,1000h        ;more than a buffer can possibly hold?
  585.     jae    buffer_free_2        ;  yes - it's hopeless
  586.  
  587. ;now give our buffer the amount that it needs.
  588.     call    adjust_new_size        ;if we don't have enough memory,
  589.  
  590.     mov    ax,free_paras        ;get the free paragraphs, and divide it
  591.     mov    dx,0            ;  evenly among all the buffers.
  592.     div    num_buffers
  593.  
  594.     mov    cx,ax            ;allocate the memory evenly.
  595.     call    adjust_all        ;adjust all the buffers.
  596.  
  597.     cmp    free_paras,0        ;is there any memory left?
  598.     je    buffer_free_3        ;no - we're done allocating.
  599.  
  600.     mov    cx,65535        ;now allocate the rest of the memory.
  601.     call    adjust_all
  602. buffer_free_3:
  603.     call    expand
  604.     clc
  605.     jmp    short buffer_free_4
  606. buffer_free_2:
  607.     stc
  608. buffer_free_4:
  609.     mov    es,saveES
  610.     pop    di
  611.     pop    si
  612.     pop    dx
  613.     pop    cx
  614.     pop    bx
  615.     mov    ax,ds
  616.     mov    ds,saveDS
  617.     ret
  618.     assume    es:data
  619.  
  620.  
  621. expand:
  622. ;exit with ds=data.
  623.     mov    ax,'*e'
  624.     call    store_debug
  625.  
  626.     call    get_last_buffer
  627. ;now we have ds=paragraph of the last buffer, dx->new location for this buffer.
  628. expand_2:
  629.     mov    ax,dx            ;get the destination paragraph.
  630.     call    move_buffer_higher    ;move the buffer up.
  631.     mov    ax,prev_buffer        ;get the previous buffer.
  632.     or    ax,ax
  633.     je    expand_1        ;go if we're done.
  634.     mov    dx,ds            ;remember where we are now.
  635.     mov    ds,ax
  636.     sub    dx,new_size        ;find out where we'll be next.
  637.     jmp    expand_2
  638. expand_1:
  639.     mov    ax,' e'
  640.     call    store_debug
  641.  
  642.     ret
  643.  
  644.  
  645. get_last_buffer:
  646. ;exit with dx = paragraph of new last buffer,
  647. ;  ds = paragraph of current last buffer.
  648.     mov    dx,ss            ;add up the new sizes of the buffers.
  649.     mov    ds,dx
  650. get_last_buffer_1:
  651.     cmp    next_buffer,0        ;is this the last buffer?
  652.     je    get_last_buffer_2    ;yes - we're done.
  653.     add    dx,new_size        ;no - add in the size of this buffer,
  654.     mov    ds,next_buffer        ;and go to the next buffer.
  655.     jmp    get_last_buffer_1
  656. get_last_buffer_2:
  657.     ret
  658.  
  659.  
  660. adjust_all:
  661. ;enter with cx = amount of memory to allocate to each buffer.
  662. ;add this amount to the new size of each buffer.
  663.     push    ds
  664.     mov    ax,ss            ;get the first buffer.
  665.     mov    ds,ax
  666. adjust_all_1:
  667.     call    adjust_new_size
  668.     mov    ax,next_buffer        ;is this the last buffer?
  669.     cmp    ax,0
  670.     mov    ds,ax
  671.     jne    adjust_all_1        ;no - go do another.
  672.     pop    ds
  673.     ret
  674.  
  675.  
  676. adjust_new_size:
  677. ;enter with ds = segment whose new_size we're adjusting.
  678. ;  free_paras = the number of free paragraphs to allocate,
  679. ;  cx = number of paragraphs to allocate to the buffer in ds.
  680. ;return with cy if we don't have enough memory to allocate that many.
  681.     mov    ax,1000h        ;get the max buffer size.
  682.     sub    ax,new_size        ;subtract off the new size.
  683.     cmp    ax,cx            ;more than we want?
  684.     jb    adjust_new_size_1    ;  no - we can only give it this much.
  685.     mov    ax,cx            ;  yes - only give it as much as we want.
  686. adjust_new_size_1:
  687.     cmp    ax,free_paras        ;more than we have?
  688.     jb    adjust_new_size_2    ;  no - we can give it this much.
  689.     mov    ax,free_paras        ;  yes - only give it as much as we have.
  690. adjust_new_size_2:
  691.     add    new_size,ax
  692.     sub    free_paras,ax        ;say that we have that many fewer.
  693.     ret
  694.  
  695.  
  696. adjust_segments:
  697. ;enter with bx = current bufseg, ax = new location of that bufseg.
  698.     push    si
  699.     push    di
  700.     mov    si,offset adjust_list
  701. adjust_segments_1:
  702.     mov    di,data:[si]        ;get the next pointer.
  703.     add    si,2
  704.     or    di,di            ;exit on null.
  705.     je    adjust_segments_2
  706.     cmp    data:[di],bx        ;is this the old one?
  707.     jne    adjust_segments_1    ;no.
  708.     mov    data:[di],ax        ;yes - update with the new.
  709.     jmp    adjust_segments_1
  710. adjust_segments_2:
  711.     pop    di
  712.     pop    si
  713.     ret
  714.  
  715.  
  716. select_buffer:
  717. ;enter with ds=buffer to select.
  718.     mov    textseg,ds        ;save the new current buffer.
  719.     mov    ax,botbot
  720.     sub    ax,toptop
  721.     mov    dx,0
  722.     mov    cx,100
  723.     div    cx
  724.     mov    memsize,ax
  725.     ret
  726.  
  727.  
  728. move_buffer_higher:
  729. ;move a buffer higher in memory.
  730. ;enter with ax = new buffer location, new_size = new buffer size (in paras).
  731.     push    es
  732.     mov    bx,ds
  733.     call    adjust_segments
  734.     mov    es,ax
  735.     assume    es:bufseg
  736.  
  737.     std                ;moving from low to high, go backwards.
  738.  
  739.     mov    si,botbot        ;get the last location used in a buffer,
  740.     dec    si
  741.  
  742.     mov    di,new_size        ;compute the new last location in the
  743.     shl    di,1            ;  buffer.
  744.     shl    di,1
  745.     shl    di,1
  746.     shl    di,1
  747.     dec    di
  748.     dec    di
  749.  
  750.     mov    cx,botbot        ;compute the amount to move.
  751.     sub    cx,bottop
  752.  
  753.     mov    botbot,di
  754.     inc    botbot
  755.     rep    movsb
  756.     mov    bottop,di
  757.     inc    bottop
  758.  
  759.     mov    si,topbot        ;now move the bottom part of the buffer.
  760.     dec    si
  761.     mov    di,si
  762.     mov    cx,topbot
  763.     rep    movsb
  764.  
  765.     cld                ;now update the previous and next ptrs.
  766.     mov    si,es:prev_buffer
  767.     mov    di,es:next_buffer
  768.  
  769.     or    si,si            ;is there a previous buffer?
  770.     je    move_buffer_higher_1    ;no.
  771.     mov    ds,si
  772.     mov    next_buffer,ax        ;tell it where we are now.
  773. move_buffer_higher_1:
  774.  
  775.     or    di,di            ;is there a next buffer?
  776.     je    move_buffer_higher_2    ;no.
  777.     mov    ds,di            ;get the next buffer.
  778.     mov    prev_buffer,ax        ;tell it where we are now.
  779. move_buffer_higher_2:
  780.  
  781.     mov    ds,ax            ;and return ds = us.
  782.     pop    es
  783.     assume    es:data
  784.     ret
  785.  
  786.  
  787. move_buffer_lower:
  788. ;move a buffer lower in memory.
  789. ;enter with ds=buffer before the one to be lowered.
  790. ;exit with ds=new location of lowered buffer.
  791.     call    buffer_paragraphs
  792.  
  793.     mov    ax,ds            ;get the base of this buffer.
  794.     add    ax,cx            ;get the end of this buffer.
  795.     mov    bx,next_buffer
  796.     mov    next_buffer,ax        ;save the pointer to the next buffer.
  797.     mov    cx,ds
  798.     mov    ds,bx            ;get paragraph of buffer to move.
  799.     mov    prev_buffer,cx        ;now remember where the previous buffer is.
  800.  
  801.     call    adjust_segments
  802.  
  803.     push    es
  804.     mov    es,ax            ;move the bottom down to the new buffer.
  805.     assume    es:bufseg
  806.     mov    si,0
  807.     mov    di,si
  808.     mov    cx,topbot
  809.     movmem
  810.  
  811.     mov    si,es:bottop        ;have to get the copy, just in case.
  812.     mov    es:bottop,di        ;save the new bottop.
  813.     mov    cx,es:botbot
  814.     sub    cx,si            ;same as sub cx,bottop
  815.     movmem
  816.     mov    es:botbot,di
  817.  
  818.     pop    es
  819.     assume    es:data
  820.     mov    ds,ax            ;get new para of just moved buffer.
  821.     ret
  822.  
  823.  
  824. buffer_paragraphs:
  825. ;compute the number of paragraphs used by a buffer.
  826. ;enter with ds=buffer
  827. ;exit with cx=number of paragraphs.
  828.     mov    cx,botbot
  829.     add    cx,10h            ;round up to next paragraph.
  830.     rcr    cx,1            ;ensure that 65536 bytes becomes
  831.     shr    cx,1            ; 1000h paragraphs.
  832.     shr    cx,1
  833.     shr    cx,1
  834.     ret
  835.  
  836.  
  837. code    ends
  838.  
  839.     end
  840.